<!-- 代码已包含 CSS：使用 TailwindCSS , 安装 TailwindCSS 后方可看到布局样式效果 -->
<template>
<div v-if="!showLayout" class="min-h-screen flex items-center justify-center bg-gradient-to-br from-blue-50 to-indigo-100" :style="{
backgroundImage: 'url(https://mastergo.com/ai/api/search-image?query=Minimalist and elegant login page background with soft geometric patterns and subtle 3D shapes floating in space. Light and airy design with gentle gradients from pure white to pale blue. Ethereal particles and light streaks create depth. Premium tech aesthetic with clean lines and modern sophistication&width=1920&height=1080&orientation=landscape&flag=adca6b32c46700e8c10e45811f1f34be)',
backgroundBlendMode: 'soft-light'
}">
<div class="w-96 backdrop-blur-md bg-white/95 rounded-lg shadow-2xl p-8 border border-white/20">
<div class="text-center mb-8">
<div class="flex flex-col items-center">
<h1 class="text-3xl font-bold tracking-tight bg-gradient-to-r from-blue-600 to-indigo-600 bg-clip-text text-transparent">宇墨云工管</h1>
<p class="text-gray-600 mt-2">欢迎回来，请登录您的账号</p>
</div>
</div>
<el-form :model="loginForm" class="space-y-6">
<el-form-item>
<el-input
v-model="loginForm.username"
placeholder="请输入用户名"
class="text-sm"
>
<template #prefix>
<el-icon><User /></el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item>
<el-input
v-model="loginForm.password"
type="password"
placeholder="请输入密码"
class="text-sm"
>
<template #prefix>
<el-icon><Lock /></el-icon>
</template>
</el-input>
</el-form-item>
<el-button
type="primary"
class="w-full !rounded-button bg-gradient-to-r from-blue-600 to-indigo-600 border-none hover:from-blue-700 hover:to-indigo-700 transition-all duration-300"
@click="handleLogin"
>
登录
</el-button>
</el-form>
</div>
</div>
<div v-else class="min-h-screen flex bg-gradient-to-br from-gray-50 to-blue-50/30">
<!-- Main Content -->
<div class="flex-1">
<!-- Main Content -->
<main class="p-6 bg-transparent">
<div v-if="activeMenu === 'admin'" class="bg-gradient-to-br from-white to-blue-50/30 p-6 min-h-[calc(100vh-4rem)]">
<!-- Admin Statistics -->
<div class="grid grid-cols-3 gap-6 mb-6">
<div class="bg-white rounded-lg shadow-sm p-6 flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">管理员总数</p>
<p class="text-2xl font-semibold mt-2">12</p>
</div>
<el-icon class="text-4xl text-blue-500"><User /></el-icon>
</div>
<div class="bg-white rounded-lg shadow-sm p-6 flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">系统管理员</p>
<p class="text-2xl font-semibold mt-2">3</p>
</div>
<el-icon class="text-4xl text-green-500"><Setting /></el-icon>
</div>
<div class="bg-white rounded-lg shadow-sm p-6 flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">企业管理员</p>
<p class="text-2xl font-semibold mt-2">9</p>
</div>
<el-icon class="text-4xl text-orange-500"><CircleCheck /></el-icon>
</div>
</div>
<!-- Search and Filter -->
<div class="bg-white rounded-lg shadow-sm p-6 mb-6">
<div class="flex items-center justify-between mb-6">
<div class="flex items-center space-x-4">
<el-select v-model="adminStatus" placeholder="启用状态" class="w-32">
<el-option label="已启用" value="enabled" />
<el-option label="未启用" value="disabled" />
</el-select>
<el-select v-model="adminRole" placeholder="角色选择" class="w-36">
<el-option label="系统管理员" value="system" />
<el-option label="企业管理员" value="enterprise" />
</el-select>
<el-input
v-model="adminSearchQuery"
placeholder="搜索管理员"
class="w-64 text-sm"
clearable
>
<template #prefix>
<el-icon><Search /></el-icon>
</template>
</el-input>
<el-button type="primary" class="!rounded-button whitespace-nowrap">
<el-icon class="mr-1"><Search /></el-icon>
搜索
</el-button>
</div>
<div class="flex items-center space-x-4">
<el-button type="success" class="!rounded-button whitespace-nowrap" @click="showAddAdmin = true">
<el-icon class="mr-1"><Plus /></el-icon>
添加管理员
</el-button>
</div>
</div>
<!-- Admin Table -->
<el-table :data="adminTableData" style="width: 100%">
<el-table-column prop="adminId" label="用户ID" width="120" />
<el-table-column prop="name" label="姓名" width="120" />
<el-table-column prop="role" label="角色" width="120">
<template #default="{ row }">
<el-tag :type="row.role === '系统管理员' ? 'danger' : 'warning'" size="small" effect="light">
{{ row.role }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="phone" label="手机号" width="140" />
<el-table-column prop="email" label="邮箱" min-width="200" />
<el-table-column prop="department" label="所属部门" width="160" />
<el-table-column prop="status" label="状态" width="100">
<template #default="{ row }">
<el-tag :type="row.status === '已启用' ? 'success' : 'info'" size="small" effect="light">
{{ row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template #default="{ row }">
<div class="flex items-center space-x-2">
<el-button type="primary" size="small" class="!rounded-button whitespace-nowrap" @click="handleEditAdmin(row)">
<el-icon class="mr-1"><Setting /></el-icon>
编辑
</el-button>
<el-button type="info" size="small" class="!rounded-button whitespace-nowrap" @click="handleViewAdminDetail(row)">
<el-icon class="mr-1"><InfoFilled /></el-icon>
详情
</el-button>
<el-button :type="row.status === '已启用' ? 'danger' : 'success'" size="small" class="!rounded-button whitespace-nowrap" @click="handleToggleAdminStatus(row)">
<el-icon class="mr-1"><SwitchButton /></el-icon>
{{ row.status === '已启用' ? '禁用' : '启用' }}
</el-button>
</div>
</template>
</el-table-column>
</el-table>
<!-- Pagination -->
<div class="flex justify-end mt-6">
<el-pagination
v-model:current-page="adminCurrentPage"
v-model:page-size="adminPageSize"
:total="adminTotal"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next"
/>
</div>
</div>
</div>
<div v-if="activeMenu === 'enterprise'" class="bg-gradient-to-br from-white to-blue-50/30 p-6 min-h-[calc(100vh-4rem)]">
<!-- Enterprise Admin Statistics -->
<div class="grid grid-cols-3 gap-6 mb-6">
<div class="bg-white rounded-lg shadow-sm p-6 flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">企业总数</p>
<p class="text-2xl font-semibold mt-2">28</p>
</div>
<el-icon class="text-4xl text-blue-500"><User /></el-icon>
</div>
<div class="bg-white rounded-lg shadow-sm p-6 flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">企业管理员</p>
<p class="text-2xl font-semibold mt-2">32</p>
</div>
<el-icon class="text-4xl text-green-500"><Setting /></el-icon>
</div>
<div class="bg-white rounded-lg shadow-sm p-6 flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">在线用户</p>
<p class="text-2xl font-semibold mt-2">156</p>
</div>
<el-icon class="text-4xl text-orange-500"><CircleCheck /></el-icon>
</div>
</div>
<!-- Search and Filter -->
<div class="bg-white rounded-lg shadow-sm p-6 mb-6">
<div class="flex items-center justify-between mb-6">
<div class="flex items-center space-x-4">
<el-select v-model="enterpriseStatus" placeholder="启用状态" class="w-32">
<el-option label="已启用" value="enabled" />
<el-option label="未启用" value="disabled" />
</el-select>
<el-select v-model="enterpriseType" placeholder="企业类型" class="w-36">
<el-option label="施工企业" value="construction" />
<el-option label="监理企业" value="supervision" />
<el-option label="设计企业" value="design" />
</el-select>
<el-input
v-model="enterpriseSearchQuery"
placeholder="搜索企业"
class="w-64 text-sm"
clearable
>
<template #prefix>
<el-icon><Search /></el-icon>
</template>
</el-input>
<el-button type="primary" class="!rounded-button whitespace-nowrap">
<el-icon class="mr-1"><Search /></el-icon>
搜索
</el-button>
</div>
<div class="flex items-center space-x-4">
<el-button type="success" class="!rounded-button whitespace-nowrap" @click="showAddAdmin = true">
<el-icon class="mr-1"><Plus /></el-icon>
添加管理员
</el-button>
</div>
<!-- 添加管理员弹窗 -->
<el-dialog
v-model="showAddAdmin"
title="添加管理员"
width="50%"
>
<!-- 编辑管理员弹窗 -->
<el-dialog
v-model="showEditAdmin"
title="编辑管理员"
width="50%"
>
<el-form :model="editingAdmin" label-width="100px" v-if="editingAdmin">
<el-form-item label="姓名" required>
<el-input v-model="editingAdmin.name" placeholder="请输入管理员姓名" />
</el-form-item>
<el-form-item label="角色" required>
<el-select v-model="editingAdmin.role" placeholder="请选择角色" class="w-full">
<el-option label="系统管理员" value="系统管理员" />
<el-option label="企业管理员" value="企业管理员" />
</el-select>
</el-form-item>
<el-form-item label="手机号" required>
<el-input v-model="editingAdmin.phone" placeholder="请输入手机号" />
</el-form-item>
<el-form-item label="邮箱" required>
<el-input v-model="editingAdmin.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="所属部门" required>
<el-select v-model="editingAdmin.department" placeholder="请选择所属部门" class="w-full">
<el-option label="信息技术部" value="信息技术部" />
<el-option label="运营管理部" value="运营管理部" />
<el-option label="技术研发部" value="技术研发部" />
<el-option label="项目管理部" value="项目管理部" />
<el-option label="客户服务部" value="客户服务部" />
</el-select>
</el-form-item>
<el-form-item label="状态">
<el-select v-model="editingAdmin.status" placeholder="请选择状态" class="w-full">
<el-option label="已启用" value="已启用" />
<el-option label="未启用" value="未启用" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="flex justify-end gap-2">
<el-button @click="showEditAdmin = false">取消</el-button>
<el-button type="primary" class="!rounded-button" @click="handleUpdateAdmin">确认修改</el-button>
</div>
</template>
</el-dialog>
<!-- 管理员详情弹窗 -->
<el-dialog
v-model="showAdminDetail"
title="管理员详情"
width="50%"
>
<div v-if="currentAdminDetail" class="space-y-6">
<div class="bg-gray-50 rounded-lg p-6">
<div class="grid grid-cols-2 gap-4">
<div class="space-y-2">
<div class="text-gray-500">管理员ID</div>
<div class="font-medium">{{ currentAdminDetail.adminId }}</div>
</div>
<div class="space-y-2">
<div class="text-gray-500">姓名</div>
<div class="font-medium">{{ currentAdminDetail.name }}</div>
</div>
<div class="space-y-2">
<div class="text-gray-500">角色</div>
<div class="font-medium">
<el-tag :type="currentAdminDetail.role === '系统管理员' ? 'danger' : 'warning'" size="small" effect="light">
{{ currentAdminDetail.role }}
</el-tag>
</div>
</div>
<div class="space-y-2">
<div class="text-gray-500">手机号</div>
<div class="font-medium">{{ currentAdminDetail.phone }}</div>
</div>
<div class="space-y-2">
<div class="text-gray-500">邮箱</div>
<div class="font-medium">{{ currentAdminDetail.email }}</div>
</div>
<div class="space-y-2">
<div class="text-gray-500">所属部门</div>
<div class="font-medium">{{ currentAdminDetail.department }}</div>
</div>
<div class="space-y-2">
<div class="text-gray-500">状态</div>
<div class="font-medium">
<el-tag :type="currentAdminDetail.status === '已启用' ? 'success' : 'info'" size="small" effect="light">
{{ currentAdminDetail.status }}
</el-tag>
</div>
</div>
<div class="space-y-2">
<div class="text-gray-500">创建时间</div>
<div class="font-medium">2023-12-01 10:00:00</div>
</div>
<div class="space-y-2">
<div class="text-gray-500">最后登录</div>
<div class="font-medium">2023-12-15 15:30:00</div>
</div>
</div>
</div>
</div>
</el-dialog>
<el-form :model="newAdmin" label-width="100px">
<el-form-item label="姓名" required>
<el-input v-model="newAdmin.name" placeholder="请输入管理员姓名" />
</el-form-item>
<el-form-item label="角色" required>
<el-select v-model="newAdmin.role" placeholder="请选择角色" class="w-full">
<el-option label="系统管理员" value="系统管理员" />
<el-option label="企业管理员" value="企业管理员" />
</el-select>
</el-form-item>
<el-form-item label="手机号" required>
<el-input v-model="newAdmin.phone" placeholder="请输入手机号" />
</el-form-item>
<el-form-item label="邮箱" required>
<el-input v-model="newAdmin.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="所属部门" required>
<el-select v-model="newAdmin.department" placeholder="请选择所属部门" class="w-full">
<el-option label="信息技术部" value="信息技术部" />
<el-option label="运营管理部" value="运营管理部" />
<el-option label="技术研发部" value="技术研发部" />
<el-option label="项目管理部" value="项目管理部" />
<el-option label="客户服务部" value="客户服务部" />
</el-select>
</el-form-item>
<el-form-item label="状态">
<el-select v-model="newAdmin.status" placeholder="请选择状态" class="w-full">
<el-option label="已启用" value="已启用" />
<el-option label="未启用" value="未启用" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="flex justify-end gap-2">
<el-button @click="showAddAdmin = false">取消</el-button>
<el-button type="primary" class="!rounded-button" @click="handleAddAdmin">确认添加</el-button>
</div>
</template>
</el-dialog>
</div>
<!-- Enterprise Table -->
<el-table :data="enterpriseTableData" style="width: 100%">
<el-table-column prop="enterpriseId" label="企业ID" width="120" />
<el-table-column prop="name" label="企业名称" width="220" />
<el-table-column prop="type" label="企业类型" width="120">
<template #default="{ row }">
<el-tag :type="row.type === '施工企业' ? 'danger' : row.type === '监理企业' ? 'warning' : 'success'" size="small" effect="light">
{{ row.type }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="contact" label="联系人" width="120" />
<el-table-column prop="phone" label="联系电话" width="140" />
<el-table-column prop="address" label="企业地址" min-width="200" />
<el-table-column prop="status" label="状态" width="100">
<template #default="{ row }">
<el-tag :type="row.status === '已启用' ? 'success' : 'info'" size="small" effect="light">
{{ row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template #default="{ row }">
<div class="flex items-center space-x-2">
<el-button type="primary" size="small" class="!rounded-button whitespace-nowrap" @click="handleEditAdmin(row)">
<el-icon class="mr-1"><Setting /></el-icon>
编辑
</el-button>
<el-button type="info" size="small" class="!rounded-button whitespace-nowrap" @click="handleViewAdminDetail(row)">
<el-icon class="mr-1"><InfoFilled /></el-icon>
详情
</el-button>
<el-button :type="row.status === '已启用' ? 'danger' : 'success'" size="small" class="!rounded-button whitespace-nowrap" @click="handleToggleAdminStatus(row)">
<el-icon class="mr-1"><SwitchButton /></el-icon>
{{ row.status === '已启用' ? '禁用' : '启用' }}
</el-button>
</div>
</template>
</el-table-column>
</el-table>
<!-- Pagination -->
<div class="flex justify-end mt-6">
<el-pagination
v-model:current-page="enterpriseCurrentPage"
v-model:page-size="enterprisePageSize"
:total="enterpriseTotal"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next"
/>
</div>
</div>
</div>
<div v-if="activeMenu === 'devices'" class="bg-gradient-to-br from-white to-blue-50/30 p-6 min-h-[calc(100vh-4rem)]">
<!-- Device Statistics -->
<div class="grid grid-cols-4 gap-6 mb-6">
<div class="bg-white rounded-lg shadow-sm p-6 flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">设备总数</p>
<p class="text-2xl font-semibold mt-2">28</p>
</div>
<el-icon class="text-4xl text-blue-500"><VideoCamera /></el-icon>
</div>
<div class="bg-white rounded-lg shadow-sm p-6 flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">在线设备</p>
<p class="text-2xl font-semibold mt-2">24</p>
</div>
<el-icon class="text-4xl text-green-500"><CircleCheck /></el-icon>
</div>
<div class="bg-white rounded-lg shadow-sm p-6 flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">离线设备</p>
<p class="text-2xl font-semibold mt-2">4</p>
</div>
<el-icon class="text-4xl text-red-500"><CircleClose /></el-icon>
</div>
<div class="bg-white rounded-lg shadow-sm p-6 flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">故障设备</p>
<p class="text-2xl font-semibold mt-2">2</p>
</div>
<el-icon class="text-4xl text-orange-500"><Warning /></el-icon>
</div>
</div>
<!-- Search and Filter -->
<div class="bg-white rounded-lg shadow-sm p-6 mb-6">
<div class="flex items-center justify-between mb-6">
<div class="flex items-center space-x-4">
<el-input
v-model="searchQuery"
placeholder="搜索设备"
class="w-64 text-sm"
clearable
>
<template #prefix>
<el-icon><Search /></el-icon>
</template>
</el-input>
<el-button type="primary" class="!rounded-button whitespace-nowrap">
<el-icon class="mr-1"><Search /></el-icon>
搜索
</el-button>
</div>
<div class="flex items-center space-x-4">
<el-button type="success" class="!rounded-button whitespace-nowrap" @click="showAddForm = true">
<el-icon class="mr-1"><Plus /></el-icon>
添加设备
</el-button>
</div>
</div>
<!-- Device Table -->
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="deviceId" label="设备ID" width="140" />
<el-table-column prop="name" label="设备名称" width="160" />
<el-table-column prop="address" label="设备地址" min-width="200" />
<el-table-column prop="serialNumber" label="序列号" width="140" />
<el-table-column prop="model" label="品牌型号" width="140" />
<el-table-column prop="type" label="摄像头类型" width="120" />
<el-table-column prop="status" label="摄像头状态" width="120">
<template #default="{ row }">
<el-tag :type="row.status === '在线' ? 'success' : 'danger'" size="small" effect="light">
{{ row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="workStatus" label="工作状态" width="120">
<template #default="{ row }">
<el-tag :type="getWorkStatusType(row.workStatus)" size="small" effect="light">
{{ row.workStatus }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="oilLevel" label="剩余油位" width="100">
<template #default="{ row }">
<span>{{ row.oilLevel }}%</span>
</template>
</el-table-column>
<el-table-column prop="workHours" label="今日工时" width="100">
<template #default="{ row }">
<span>{{ row.workHours }}h</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180" fixed="right">
<template #default="{ row }">
<div class="flex items-center space-x-4">
<a href="javascript:;" class="text-blue-600 hover:text-blue-700" @click="handleEditDevice(row)">
<el-icon class="mr-1 text-xs"><Edit /></el-icon>
编辑
</a>
<a href="javascript:;" class="text-gray-600 hover:text-gray-700" @click="showDeviceDetail(row)">
<el-icon class="mr-1 text-xs"><InfoFilled /></el-icon>
详情
</a>
<a href="javascript:;" class="text-red-600 hover:text-red-700" @click="handleDeleteDevice(row)">
<el-icon class="mr-1 text-xs"><Delete /></el-icon>
删除
</a>
</div>
</template>
</el-table-column>
</el-table>

<!-- 添加设备弹窗 -->
<el-dialog
v-model="showAddForm"
title="添加设备"
width="50%"
>
<el-form :model="newDevice" label-width="100px">
<el-form-item label="设备SN号" required>
<el-input v-model="newDevice.serialNumber" placeholder="请输入设备SN号" />
</el-form-item>
<el-form-item label="设备名称" required>
<el-input v-model="newDevice.name" placeholder="请输入设备名称" />
</el-form-item>
<el-form-item label="设备型号">
<el-input value="HIKVISION DS-2DC" disabled />
</el-form-item>
<el-form-item label="摄像头序列号" required>
<el-input v-model="newDevice.cameraSerialNumber" placeholder="请输入摄像头序列号" />
</el-form-item>
<el-form-item label="摄像头类型" required>
<el-select v-model="newDevice.type" placeholder="请选择摄像头类型" class="w-full">
<el-option label="云台高速球" value="云台高速球" />
<el-option label="枪式摄像机" value="枪式摄像机" />
<el-option label="半球摄像机" value="半球摄像机" />
</el-select>
</el-form-item>
<el-form-item label="所属组织" required>
<el-select v-model="newDevice.organization" placeholder="请选择所属组织" class="w-full">
<el-option label="杭州建工集团/杭州建工集团工程公司/钱江世纪城项目部" value="杭州建工集团/杭州建工集团工程公司/钱江世纪城项目部" />
<el-option label="中天建设集团/中天建设集团工程公司/未来科技城项目部" value="中天建设集团/中天建设集团工程公司/未来科技城项目部" />
<el-option label="浙江省建工集团/浙江省建工集团工程公司/滨江科技园项目部" value="浙江省建工集团/浙江省建工集团工程公司/滨江科技园项目部" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="flex justify-end gap-2">
<el-button @click="showAddForm = false">取消</el-button>
<el-button type="primary" class="!rounded-button whitespace-nowrap" @click="handleAddDevice">确认添加</el-button>
</div>
</template>
</el-dialog>
<!-- 编辑设备弹窗 -->
<el-dialog
v-model="showEditForm"
title="编辑设备"
width="50%"
>
<div v-if="editingDevice" class="space-y-6">
<el-form :model="editingDevice" label-width="100px">
<el-form-item label="设备序列号" required>
<el-input v-model="editingDevice.serialNumber" disabled />
</el-form-item>
<el-form-item label="设备名称">
<el-input v-model="editingDevice.name" />
</el-form-item>
<el-form-item label="设备型号">
<el-input v-model="editingDevice.model" disabled />
</el-form-item>
<el-form-item label="摄像头序列号" required>
<el-input v-model="editingDevice.cameraSerialNumber" placeholder="请输入摄像头序列号" />
</el-form-item>
<el-form-item label="摄像头类型">
<el-select v-model="editingDevice.type" class="w-full">
<el-option label="云台高速球" value="云台高速球" />
<el-option label="枪式摄像机" value="枪式摄像机" />
<el-option label="半球摄像机" value="半球摄像机" />
</el-select>
</el-form-item>
<el-form-item label="所属组织" required>
<el-select v-model="editingDevice.organization" placeholder="请选择所属组织" class="w-full">
<el-option label="杭州建工集团/杭州建工集团工程公司/钱江世纪城项目部" value="杭州建工集团/杭州建工集团工程公司/钱江世纪城项目部" />
<el-option label="中天建设集团/中天建设集团工程公司/未来科技城项目部" value="中天建设集团/中天建设集团工程公司/未来科技城项目部" />
<el-option label="浙江省建工集团/浙江省建工集团工程公司/滨江科技园项目部" value="浙江省建工集团/浙江省建工集团工程公司/滨江科技园项目部" />
</el-select>
</el-form-item>
</el-form>
<div class="flex justify-end gap-2">
<el-button @click="showEditForm = false">取消</el-button>
<el-button type="primary" class="!rounded-button" @click="handleUpdateDevice">确认</el-button>
</div>
</div>
</el-dialog>
<!-- Pagination -->
<div class="flex justify-end mt-6">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:total="total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next"
/>
</div>
</div>
</div>
</main>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onUnmounted } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import {
House,
VideoCamera,
VideoPlay,
List,
Setting,
Search,
Bell,
Delete,
Edit,
InfoFilled,
Histogram,
Grid,
ArrowDown,
ArrowUp,
ArrowLeft,
ArrowRight,
SwitchButton,
User,
Lock,
Timer,
Location,
FullScreen,
ZoomIn,
ZoomOut,
Microphone,
CircleCheck,
CircleClose,
Warning,
Plus
} from '@element-plus/icons-vue';
const activeMenu = ref('devices');
const gridType = ref(4);
const searchQuery = ref('');
const currentPage = ref(1);
const pageSize = ref(20);
const total = ref(28);
// Admin page
const adminStatus = ref('');
const adminRole = ref('');
const adminSearchQuery = ref('');
const adminCurrentPage = ref(1);
const adminPageSize = ref(20);
const adminTotal = ref(2);
const showAddAdmin = ref(false);
const showEditAdmin = ref(false);
const showAdminDetail = ref(false);
const editingAdmin = ref<any>(null);
const currentAdminDetail = ref<any>(null);
const newAdmin = ref({
name: '',
role: '系统管理员',
phone: '',
email: '',
department: '',
status: '已启用'
});
const handleEditAdmin = (admin: any) => {
editingAdmin.value = { ...admin };
showEditAdmin.value = true;
};
const handleToggleAdminStatus = (admin: any) => {
ElMessageBox.confirm(
`确定要${admin.status === '已启用' ? '禁用' : '启用'}该管理员吗？`,
'操作确认',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
const index = adminTableData.value.findIndex(item => item.adminId === admin.adminId);
if (index > -1) {
adminTableData.value[index].status = admin.status === '已启用' ? '未启用' : '已启用';
ElMessage({
type: 'success',
message: `${admin.status === '已启用' ? '禁用' : '启用'}成功`
});
}
}).catch(() => {
// 取消操作
});
};
const handleUpdateAdmin = () => {
if (!editingAdmin.value.name || !editingAdmin.value.phone || !editingAdmin.value.email || !editingAdmin.value.department) {
ElMessage({
type: 'warning',
message: '请填写所有必填项'
});
return;
}
const phoneRegex = /^1[3-9]\d{9}$/;
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!phoneRegex.test(editingAdmin.value.phone)) {
ElMessage({
type: 'error',
message: '请输入正确的手机号码'
});
return;
}
if (!emailRegex.test(editingAdmin.value.email)) {
ElMessage({
type: 'error',
message: '请输入正确的邮箱地址'
});
return;
}
const index = adminTableData.value.findIndex(item => item.adminId === editingAdmin.value.adminId);
if (index > -1) {
adminTableData.value[index] = { ...editingAdmin.value };
ElMessage({
type: 'success',
message: '更新管理员信息成功'
});
showEditAdmin.value = false;
}
};
const handleViewAdminDetail = (admin: any) => {
currentAdminDetail.value = {
...admin,
createTime: '2023-12-01 10:00:00',
lastLoginTime: '2023-12-15 15:30:00'
};
showAdminDetail.value = true;
};
const handleAddAdmin = () => {
if (!newAdmin.value.name || !newAdmin.value.phone || !newAdmin.value.email || !newAdmin.value.department) {
ElMessage({
type: 'warning',
message: '请填写所有必填项'
});
return;
}
// 表单验证
const phoneRegex = /^1[3-9]\d{9}$/;
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!phoneRegex.test(newAdmin.value.phone)) {
ElMessage({
type: 'error',
message: '请输入正确的手机号码'
});
return;
}
if (!emailRegex.test(newAdmin.value.email)) {
ElMessage({
type: 'error',
message: '请输入正确的邮箱地址'
});
return;
}
const admin = {
adminId: `AD${Date.now().toString().slice(-6)}`,
...newAdmin.value
};
adminTableData.value.unshift(admin);
adminTotal.value++;
ElMessage({
type: 'success',
message: '添加管理员成功'
});
// 重置表单
newAdmin.value = {
name: '',
role: '系统管理员',
phone: '',
email: '',
department: '',
status: '已启用'
};
showAddAdmin.value = false;
};
const adminTableData = ref([
{
adminId: 'AD001',
name: '张明浩',
role: '系统管理员',
phone: '13812345678',
email: 'zhmh@example.com',
department: '信息技术部',
status: '已启用'
},
{
adminId: 'AD003',
name: '王建国',
role: '系统管理员',
phone: '13712345678',
email: 'wjg@example.com',
department: '技术研发部',
status: '未启用'
}
]);
const userAvatar = 'https://ai-public.mastergo.com/ai/img_res/da2183d532ddb9b665654447275e4172.jpg';
const tableData = [
{
deviceId: 'DEV20230601001',
name: '工地监控摄像头 A1',
address: '浙江省杭州市余杭区创新科技园B区12号楼',
serialNumber: 'SN202306001',
model: 'HIKVISION DS-2DC',
type: '云台高速球',
status: '在线',
workStatus: '正常运行',
oilLevel: 85,
workHours: 8.5
},
{
deviceId: 'DEV20230601002',
name: '工地监控摄像头 B2',
address: '浙江省杭州市滨江区江南大道3588号',
serialNumber: 'SN202306002',
model: 'DAHUA IPC-HFW',
type: '枪式摄像机',
status: '离线',
workStatus: '故障',
oilLevel: 45,
workHours: 3.2
},
{
deviceId: 'DEV20230601003',
name: '工地监控摄像头 C3',
address: '浙江省杭州市西湖区西溪路528号',
serialNumber: 'SN202306003',
model: 'HIKVISION DS-2CD',
type: '半球摄像机',
status: '在线',
workStatus: '正常运行',
oilLevel: 92,
workHours: 7.8
},
{
deviceId: 'DEV20230601004',
name: '工地监控摄像头 D4',
address: '浙江省杭州市拱墅区莫干山路972号',
serialNumber: 'SN202306004',
model: 'UNIVIEW IPC-2124',
type: '云台高速球',
status: '在线',
workStatus: '正常运行',
oilLevel: 78,
workHours: 6.5
},
{
deviceId: 'DEV20230601005',
name: '工地监控摄像头 E5',
address: '浙江省杭州市上城区钱江路58号',
serialNumber: 'SN202306005',
model: 'DAHUA IPC-HDBW',
type: '枪式摄像机',
status: '在线',
workStatus: '待维护',
oilLevel: 35,
workHours: 4.2
}
];
const isPlaying = ref<number | null>(null);
const showEnlargedVideo = ref(false);
const enlargedVideoIndex = ref<number | null>(null);
const enlargedVideoRef = ref<HTMLVideoElement | null>(null);

const startPlaying = (index: number) => {
if (isPlaying.value === index) {
isPlaying.value = null;
} else {
isPlaying.value = index;
}
};
const enlargeVideo = (index: number) => {
enlargedVideoIndex.value = index;
showEnlargedVideo.value = true;
// 延迟一帧等待 DOM 更新后设置播放速度
nextTick(() => {
if (enlargedVideoRef.value) {
enlargedVideoRef.value.playbackRate = 0.6;
}
});
};
const handleCloseVideo = () => {
showEnlargedVideo.value = false;
enlargedVideoIndex.value = null;
};
const handleZoom = (type: 'in' | 'out') => {
// 这里可以调用相机变焦控制的API
console.log('Zoom control:', type);
};

const getOilLevelColor = (level: number) => {
if (level >= 70) return '#67C23A';
if (level >= 30) return '#E6A23C';
return '#F56C6C';
};
const handleSelect = (index: string) => {
activeMenu.value = index;
// 切换菜单时停止视频播放
isPlaying.value = null;
};
// 组件卸载时停止视频播放
onUnmounted(() => {
isPlaying.value = null;
});
const getWorkStatusType = (status: string) => {
const statusMap: Record<string, string> = {
'正常运行': 'success',
'故障': 'danger',
'待维护': 'warning'
};
return statusMap[status] || 'info';
};
const isLogin = ref(true);
const loginForm = ref({
username: '',
password: ''
});
const handleLogin = () => {
isLogin.value = true;
};
const handleLogout = () => {
isLogin.value = false;
};
const showAddForm = ref(false);
const showEditForm = ref(false);
const editingDevice = ref<any>(null);
const newDevice = ref({
name: '',
serialNumber: '',
cameraSerialNumber: '',
type: '',
organization: ''
});
const handleEditDevice = (device: any) => {
editingDevice.value = { ...device };
showEditForm.value = true;
};
const handleUpdateDevice = () => {
// 这里可以处理设备更新逻辑
showEditForm.value = false;
editingDevice.value = null;
};
const handleAddDevice = () => {
// 验证必填字段
if (!newDevice.value.name || !newDevice.value.serialNumber || !newDevice.value.cameraSerialNumber || !newDevice.value.type) {
ElMessage({
type: 'warning',
message: '请填写所有必填项'
});
return;
}
// 创建新设备
const device = {
deviceId: `DEV${Date.now()}`,
...newDevice.value,
status: '在线',
workStatus: '正常运行',
oilLevel: 100,
workHours: 0
};
// 添加到表格数据中
tableData.unshift(device);
total.value++;
// 显示成功消息
ElMessage({
type: 'success',
message: '添加设备成功'
});
// 清空表单并关闭弹窗
newDevice.value = {
name: '',
serialNumber: '',
cameraSerialNumber: '',
type: ''
};
showAddForm.value = false;
};
const handleDeleteDevice = (device: any) => {
ElMessageBox.confirm(
`确定要删除设备"${device.name}"吗？`,
'删除确认',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
// 从 tableData 中删除设备
const index = tableData.findIndex(item => item.deviceId === device.deviceId);
if (index > -1) {
tableData.splice(index, 1);
total.value--;
ElMessage({
type: 'success',
message: '删除成功'
});
}
}).catch(() => {
// 取消删除操作
});
};
const showLayout = computed(() => isLogin.value);
</script>
<style scoped>
:deep(.el-menu) {
border-right: none;
}
:deep(.el-menu-item.is-active) {
background-color: rgba(59, 130, 246, 0.1);
border-left: 4px solid #3B82F6;
color: #3B82F6;
}
:deep(.el-menu-item:hover) {
background-color: rgba(59, 130, 246, 0.05);
}
:deep(.el-input__wrapper) {
box-shadow: 0 0 0 1px rgba(0,0,0,0.1);
}
:deep(.el-input__wrapper:hover) {
box-shadow: 0 0 0 1px rgba(0,0,0,0.2);
}
:deep(.el-form-item) {
margin-bottom: 0;
}
.text-primary {
color: #3B82F6;
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
</style>
